package org.jackysoft.service.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.FastArrayList;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.jackysoft.data.SortInfo;
import org.jackysoft.entity.HibernateCurrentStep;
import org.jackysoft.entity.HibernateHistoryStep;
import org.jackysoft.entity.HibernateStep;
import org.jackysoft.entity.User;
import org.jackysoft.entity.WorkflowEntry;
import org.jackysoft.opensymphony.workflow.entity.ActionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.WorkflowDescriptor;
import org.jackysoft.service.AbstractLongIdServiceImpl;
import org.jackysoft.service.VariableService;
import org.jackysoft.service.WorkItemService;
import org.jackysoft.service.WorkflowService;
import org.jackysoft.util.CollectionUtils;
import org.jackysoft.util.DateUtils;
import org.jackysoft.util.SpringSecurityUtils;
import org.jackysoft.util.WorkflowConstant;
import org.jackysoft.util.WorkflowUtil;
import org.jackysoft.workflow.Step2WorkItemTransformer;
import org.jackysoft.workflow.WorkItem;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly=true)
public class WorkItemServiceImpl extends AbstractLongIdServiceImpl<WorkItem> implements WorkItemService {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4832022488318900004L;
	public  static final Map<WorkflowConstant, Class<?>> queryClassName = new HashMap<WorkflowConstant, Class<?>>() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -4551582938978389951L;

		{
			put(WorkflowConstant.STATE_UNDERWAY, HibernateCurrentStep.class);
			put(WorkflowConstant.STATE_FINISHED, HibernateHistoryStep.class);
			put(WorkflowConstant.ALL_CURRENT, HibernateCurrentStep.class);
			put(WorkflowConstant.ALL_HISTORY, HibernateHistoryStep.class);
		}
	};
	private WorkflowService workflowService;
    private VariableService variableService;
	@Override
	public Iterable<WorkItem> getData(int start, int size,
			boolean listAll, SortInfo sortInfo, Map<String, Object> smap) {
		WorkflowConstant wc = WorkflowService.LOCAL_STATUS.get();
		if (wc != null) {

			switch (wc) {
			case ALL_CURRENT:				
			case ALL_HISTORY:
				return getWorkItems(start, size);
			case STATE_UNDERWAY:				
			case STATE_FINISHED:
				return getMyWorkItem(start, size);
			case STATE_WATCHOR:
				return watchWorkflow();
			default:
				return Collections.emptyList();
			}
		}

		return Collections.emptyList();
	}

	@Override
	public int getSize(SortInfo sortInfo, Map<String, Object> smap) {
		WorkflowConstant status = WorkflowService.LOCAL_STATUS.get();
		User owner = SpringSecurityUtils.getCurrentUser();
		Class<?> className = queryClassName.get(status);
		StringBuffer hql = new StringBuffer();
		if (status.equals(WorkflowConstant.STATE_FINISHED)
				|| status.equals(WorkflowConstant.STATE_UNDERWAY)) {
			hql.append("select count(*) from ");
			hql.append(className.getName()).append(" as stp ");
			hql.append(" where stp.status='").append(status.toString() + "' ");
			hql.append(" and stp.owner='").append(owner.getUsername() + "' ");
			if (status.compareTo(WorkflowConstant.STATE_UNDERWAY) == 0) {
				hql.append(" and stp.entry.state<>").append(
						WorkflowEntry.COMPLETED);
				hql.append(" and stp.entry.state<>").append(
						WorkflowEntry.KILLED);
			}
			hql.append(" group by stp.entry");
			Query query = getSession().createQuery(hql.toString());

			int size = query.list().size();
			return size;
		} else if (status.equals(WorkflowConstant.ALL_CURRENT)) {
			hql.append("select count(*) from ").append(className.getName());
			hql.append(" group by entry");
			Query query = getSession().createQuery(hql.toString());
			Object size = query.uniqueResult();
			return size==null?0:Integer.parseInt(size.toString());
		} else if (status.equals(WorkflowConstant.ALL_HISTORY)) {
			hql.append("select count(*) from ").append(className.getName());
			hql.append(" group by entry");
			Query query = getSession().createQuery(hql.toString());
			int size = query.list().size();
			// log.info(hql);
			return size;
		} else if (status.equals(WorkflowConstant.STATE_WATCHOR)) {
			return getWatchItemSize();
		} else {
			throw new IllegalStateException("非法的状态参数 : " + status);
		}

	}
			
	@Override
	public List<WorkItem> getMyWorkItem(Integer index, Integer size) {
		WorkflowConstant status = WorkflowService.LOCAL_STATUS.get();
		User owner = SpringSecurityUtils.getCurrentUser();
		Class<?> className = queryClassName.get(status);
		final List<WorkItem> works = new ArrayList<WorkItem>();
		Session session = getSession();
		List<HibernateStep> list = null;
		StringBuffer hql = new StringBuffer("from ");
		hql.append(className.getName()).append(" as stp ");
		hql.append(" where stp.status='").append(status.toString());
		hql.append("' and stp.owner='").append(owner.getUsername() + "' ");
		if (status.compareTo(WorkflowConstant.STATE_UNDERWAY) == 0) {
			hql.append(" and stp.entry.state<>")
					.append(WorkflowEntry.COMPLETED);
			hql.append(" and stp.entry.state<>").append(WorkflowEntry.KILLED);
		}
		hql.append(" group by stp.entry ");
		hql.append(" order by stp.startDate desc ,stp.finishDate desc");
		Query query = session.createQuery(hql.toString());
		query.setFirstResult(index);
		query.setMaxResults(size);
		list = query.list();
		CollectionUtils.collect(list, new Step2WorkItemTransformer(variableService, workflowService), works);
	    org.jackysoft.util.CollectionUtils.notNullable(works);
		Collections.sort(works, new Comparator<WorkItem>() {

			@Override
			public int compare(WorkItem o1, WorkItem o2) {
				if (o2.getSendDate() == null)
					return 0;
				return o2.getSendDate().compareTo(o1.getSendDate());
			}

		});
		return works;
	}

	@Override
	public List<WorkItem> getWorkItems(int start, int size) {
		WorkflowConstant status = WorkflowService.LOCAL_STATUS.get();
		Class<?> className = queryClassName.get(status);
		final List<WorkItem> works = new ArrayList<WorkItem>();
		Session session = getSession();
		List<HibernateStep> list = null;
		StringBuffer hql = new StringBuffer("from ");
		hql.append(className.getName());
		hql.append(" group by entry");
		hql.append(" order by startDate desc");
		Query query = session.createQuery(hql.toString());
		query.setFirstResult(start);
		query.setMaxResults(size);
		list = query.list();
		CollectionUtils.collect(list, new Step2WorkItemTransformer(variableService, workflowService), works);
		CollectionUtils.notNullable(works);
		return works;
	}

	@Override
	public List<WorkItem> watchWorkflow() {

		long entityId = WorkflowService.CURRENT_WORKFLOWID.get();
		String wname = getWorkflowName(entityId);
		WorkflowDescriptor wd = workflowService.getWorkflowDescriptor(wname);

		List steps = new ArrayList();
		List<WorkItem> views = new FastArrayList();

		try {
			steps.addAll(workflowService.findCurrentSteps(entityId));
			steps.addAll(workflowService.findHistorySteps(entityId));

			String cowner = "";
			for (Iterator iterator = steps.iterator(); iterator.hasNext();) {
				HibernateStep step = (HibernateStep) iterator.next();
				String owner = step.getOwner();
				// log.info("Current owner : "+owner);
				String sender = WorkflowUtil.getVarStringValue(entityId,
						WorkflowConstant.SENDER.toString());

				User cuser = null;
				if (owner != null)
					cuser = workflowService.getActor(owner);

				if (cuser != null)
					cowner = cuser.getLocalName();
				else
					cowner = owner;
				ActionDescriptor action = wd.getAction(step.getActionId());
				WorkItem view = new WorkItem();
				view.setWorkflowId(entityId);
				view.setWorkflowName(wd.getWorkflowName());
				view.setStepName(wd.getStep(step.getStepId()).getName());
				view.setGlobalStepId(step.getId());
				view.setStepId(step.getStepId());
				view.setActionName(action == null ? "请重办..." : action.getName());
				view.setOwner(owner + "[" + cowner + "]");
				view.setStatus(step.getStatus());
				view.setState(step.getEntry().getState());
				view.setSender(sender);
				view.setStartDate(DateUtils.formatDate(step.getStartDate()));
				view.setFinishDate(DateUtils.formatDate(step.getFinishDate()));
				view.setPrevIds(step.getPreviousStepIds());
				views.add(view);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return views;
	}

	@Override
	public int getWatchItemSize() {
		Session session = getSession();
		long entryId = WorkflowService.CURRENT_WORKFLOWID.get();
		String hql = "select count(*) " + "from "
				+ "(select * from os_currentstep where entry_id=" + entryId
				+ " union " + "select * from os_historystep where entry_id="
				+ entryId + ") m";

		SQLQuery query = session.createSQLQuery(hql);
		Object size = query.uniqueResult();
		return ((BigInteger) size).intValue();
	}

	String getWorkflowName(Long entryId) {
		return workflowService.findEntry(entryId).getWorkflowName();

	}
	@Resource
	public void setVariableService(VariableService variableService) {
		this.variableService = variableService;
	}
	
	@Override
	public WorkflowService getWorkflowService() {
		return this.workflowService;
	}

	@Resource
	public void setWorkflowService(WorkflowService workflowService) {
		this.workflowService = workflowService;
	}
}
